#include <linux/myhead_for_driver.h>
#include "m74hc595_driver.h"
// &spi4{
//     pinctrl-names  = "default","sleep";
//     pinctrl-0   = <&spi4_pins_b>;
//     pinctrl-1   = <&spi4_sleep_pins_b>;
//     cs-gpios = <&gpioe 11 0>; //片选管脚
//     status = "okay";
//     m74hc595@0{
//         compatible = "rhf,spi";
//         reg = <0>;
//         spi-max-frequency = <10000000>; //10MHz
//   //spi-cpol;         //代表使用mode0模式
//   //spi-cpha;
//     };
// };

#define CDEV_NAME "m74hc595_driver"
#define CDEV_NAME_CLS "m74hc595_driver_info"

struct spi_device *spi_global;

int major;
int minor;
struct cdev *cdev;
struct class *cls;
struct device *dev;

// struct i2c_client *client_global;

int m74hc595_open(struct inode *inode, struct file *file)
{

    return 0;
}

ssize_t (*read)(struct file *file, char __user *ubuf, size_t size, loff_t *loff);

ssize_t (*write)(struct file *file, const char __user *ubuf, size_t size, loff_t *loff);

long m74hc595_ioctl(struct file *file, unsigned int cmd, unsigned long args)
{
    u8 buf[2];
    u8 buf_t[2] = {0x0, 0x0};
    u8 nix_num = GET_FUNC_FROM_CMD(cmd);
    if (nix_num == 0xFF)
    {
        spi_write(spi_global, buf_t, 2);
        return 0;
    }
    if (args > 3 && cmd > 0xF)
    {
        return -EAGAIN;
    }
    buf[0] = which_tube[args];
    if (args == tube_2)
    {
        buf[1] = nixie_tube_nums[nix_num] | 0x80;
    }
    else
    {
        buf[1] = nixie_tube_nums[nix_num];
    }
    spi_write(spi_global, buf, 2);
    return 0;
}

int m74hc595_close(struct inode *inode, struct file *file)
{

    return 0;
}

static const struct file_operations m74hc595_fops = {
    .open = m74hc595_open,
    .unlocked_ioctl = m74hc595_ioctl,
    .release = m74hc595_close,
};

int m74hc595_probe(struct spi_device *spi)
{
    int err, res;
    dev_t dev_num;
    spi_global = spi;

    cdev = cdev_alloc();
    if (NULL == cdev)
    {
        err = -ENOMEM;
        goto ERR1;
    }
    cdev_init(cdev, &m74hc595_fops);
    if ((res = alloc_chrdev_region(&dev_num, 0, 1, CDEV_NAME)))
    {
        err = res;
        goto ERR2;
    }
    major = MAJOR(dev_num);
    minor = MINOR(dev_num);
    if ((res = cdev_add(cdev, MKDEV(major, minor), 1)))
    {
        err = res;
        goto ERR3;
    }
    cls = class_create(THIS_MODULE, CDEV_NAME_CLS);
    if (IS_ERR(cls))
    {
        err = PTR_ERR(cls);
        goto ERR4;
    }
    dev = device_create(cls, NULL, MKDEV(major, minor), NULL, CDEV_NAME);
    if (IS_ERR(dev))
    {
        err = PTR_ERR(dev);
        goto ERR5;
    }

    return 0;

ERR5:
    class_destroy(cls);
ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(MKDEV(major, minor), 1);
ERR2:
    kfree(cdev);
ERR1:
    return err;
}
int m74hc595_remove(struct spi_device *spi)
{
    u8 buf[2] = {0x0, 0x0};
    spi_write(spi_global, buf, 2);
    // if(can_free_xxx)
    device_destroy(cls, MKDEV(major, minor));
    class_destroy(cls);
    cdev_del(cdev);
    unregister_chrdev_region(MKDEV(major, minor), 1);
    kfree(cdev);
    return 0;
}

struct of_device_id oftable[] = {
    {
        .compatible = "rhf,spi",
    },
    {},
};

struct spi_driver m74hc595_drv = {
    .probe = m74hc595_probe,
    .remove = m74hc595_remove,
    .driver = {
        .name = "rhf",
        .of_match_table = oftable,
    },
};

static int __init m74hc595_driver_init(void)
{
    return spi_register_driver(&m74hc595_drv); // 错误判断
}

static void __exit m74hc595_driver_exit(void)
{
    spi_unregister_driver(&m74hc595_drv);
    return;
}

module_init(m74hc595_driver_init);
module_exit(m74hc595_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("rhf xxx@xxx.com");